
package org.spp.voronoi;

import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math.util.MathUtils;

/**
 * Cell.java
 * @author Ilio Catallo, Eleonora Ciceri
 * @version 1.0
 * 
 * Description: the class implements a 3D cell for the VoronoiDiagram
 * 
 * Date: Jul 22, 2011
 */
public class Cell2D extends Cell {
    
   /**
     * Constructor for the class Cell2D
     * @param centroid
     * @param voronoiDiagram 
     */    
    public Cell2D(Centroid centroid, VoronoiDiagram voronoiDiagram) {
        super(centroid, voronoiDiagram);
    }
    
    /**
     * Constructor for the cell2D
     * @param centroid
     * @param id
     * @param voronoiDiagram 
     */    
    public Cell2D(Centroid centroid, int id, VoronoiDiagram voronoiDiagram)  {
        super(centroid, id, voronoiDiagram);
    }
    
    /**
     * Method for the creation of a new facet inside the cell
     * @param firstCentroid
     * @param secondCentroid
     * @return newFacet
     */
    @Override
    protected Facet createNewFacet(Centroid firstCentroid, Centroid secondCentroid) {
        Facet newLine = new Line(firstCentroid, secondCentroid);
        return newLine;
    }        
    
    /**
     * Method that performs the vertex enumeration starting from the facets of the cell
     * @param A
     * @param b
     * @return vertexes
     */
    @Override
    protected List<Vertex> vertexEnumeration(Jama.Matrix A, Jama.Matrix b){
        // Variables
        List<Vertex> newVertexes = new ArrayList<Vertex>();
        
        // For each triplet of planes it computes the related vertex
        for(int i = 0; i < facets.size() - 1; i++)
            for(int j = i + 1; j < facets.size(); j++){                    
                int[] rows = {i, j};

                Jama.Matrix subA = A.getMatrix(rows, 0, 1);
                Jama.Matrix subb = b.getMatrix(rows, 0, 0);

                if (subA.det() == 0)
                    continue;

                // Solve the linear system
                Jama.Matrix vertex = subA.solve(subb);
                Vertex newVertex = new Vertex2D(vertex.getArray());

                //Check if the vertex just computed actually belongs to the cell
                if (!isOutside(A, b, vertex)) {
                    Vertex oldVertex = isVertexInAdjCells(newVertex);

                    // Check if already exists the same vertex in an adjacent cell
                    if (oldVertex == null){
                        newVertex.addCell(this);
                        newVertexes.add(newVertex);
                    } 
                    else 
                        oldVertex.addCell(this);
                }                                        
            }
        
        return newVertexes;        
    }    
    
    /**
     * After the vertex enumeration we can check which facets of the bounded
     * region are shared with the cell, and remove the others from the list
     * of the cell facets
     */
    @Override
    protected void removeBoundedRegionFacets(){
        // Variables
        Double minX = Double.POSITIVE_INFINITY;
        Double minY = Double.POSITIVE_INFINITY;
        
        Double maxX = Double.NEGATIVE_INFINITY;
        Double maxY = Double.NEGATIVE_INFINITY;
        
        for(int i=0;i<vertexes.size();i++){            
            // Find the min value for each coordinate
            if (vertexes.get(i).getCoordinates()[0] < minX)
                minX = vertexes.get(i).getCoordinates()[0];
            
            if (vertexes.get(i).getCoordinates()[1] < minY)
                minY = vertexes.get(i).getCoordinates()[1];
            
            // Find the max value for each coordinate
            if (vertexes.get(i).getCoordinates()[0] > maxX)
                maxX = vertexes.get(i).getCoordinates()[0];
            
            if (vertexes.get(i).getCoordinates()[1] > maxY)
                maxY = vertexes.get(i).getCoordinates()[1];           
        }
        
        if (Math.abs(minY + (Double)0.5) > MathUtils.EPSILON){
            facets.get(3).removeCell(this);
            facets.remove(3);
        }
        
        if (Math.abs(maxY - (Double)0.5) > MathUtils.EPSILON){
            facets.get(2).removeCell(this);
            facets.remove(2);
        }
        
        if (Math.abs(minX + (Double)0.5) > MathUtils.EPSILON){
            facets.get(1).removeCell(this);
            facets.remove(1);    
        }
        
        if (Math.abs(maxX - (Double)0.5) > MathUtils.EPSILON){
            facets.get(0).removeCell(this);
            facets.remove(0);
        }
    }    
}